package conf

import (
	"encoding/json"
	"time"

	"chainmaker.org/chainmaker/smarteditor/common"
	"chainmaker.org/chainmaker/smarteditor/db"
	"github.com/jinzhu/gorm"
)

type DeployInfoModel struct {
	UserId       string `gorm:"column:user_id;unique_index:uid_c;index:uid_src;index:uid_bin;index:uid_ts;index:uid_dts"`
	ContractName string `gorm:"column:contract;unique_index:uid_c"`
	SrcMd5       string `gorm:"column:src_md5;index:uid_src;index:uid_src"`
	BinMd5       string `gorm:"column:bin_md5;index:uid_bin"`
	BuildTime    int64  `gorm:"column:build_time;index:uid_ts"`
	// CreatedAt    int64  `gorm:"column:created_at"`
	// UpdatedAt    int64  `gorm:"column:updated_at"`
	DeployTime int64  `gorm:"column:deploy_time;index:uid_dts"`
	Host       string `gorm:"column:host"`
	//Path       string `gorm:"column:path;size:1024"`
	Methods     []string `gorm:"-"`
	MethodsInDB string   `gorm:"column:methods;type:text"`
}

func (*DeployInfoModel) TableName() string {
	return "deploy_infos"
}

// GetDeployList 根据用户id,分页查询已经部署程序, deployTime为上一页最后一条记录
func GetDeployList(userId string, page, pageSize int64) ([]DeployInfoModel, int, error) {
	var total int
	var retList []DeployInfoModel
	totalErr := db.GlobalDB.Model(&DeployInfoModel{}).Where("user_id = ?", userId).Count(&total).Error
	if totalErr != nil {
		log.Errorf("GetDeployList count userId %s failed %s", userId, totalErr.Error())
		return retList, total, totalErr
	}
	queryDB := db.GlobalDB.Model(&DeployInfoModel{}).Where("user_id = ?", userId)
	var queryErr error
	if pageSize == -1 {
		queryErr = queryDB.Order("deploy_time desc").Scan(&retList).Error
	} else {
		queryErr = queryDB.Order("deploy_time desc").Limit(pageSize).Offset((page - 1) * pageSize).Scan(&retList).Error
	}

	if queryErr != nil {
		log.Errorf("GetDeployList userId %s, failed %s", userId, queryErr.Error())
		return retList, total, queryErr
	}
	for i := 0; i < len(retList); i++ {
		unMarshalErr := json.Unmarshal([]byte(retList[i].MethodsInDB), &retList[i].Methods)
		if unMarshalErr != nil {
			log.Errorf("GetDeployList unmarshal failed %s", unMarshalErr.Error())
			continue
		}
	}
	return retList, total, nil
}

func DeleteDeployInfo(userId string, contractName string) error {
	return db.GlobalDB.Model(&DeployInfoModel{}).Where("user_id = ?", userId).Where("contract = ?", contractName).Delete(&DeployInfoModel{}).Error
}

func SaveDeployInfo(data *DeployInfoModel) error {
	methodsBs, marshalErr := json.Marshal(data.Methods)
	if marshalErr != nil {
		log.Errorf("SaveDeployInfo marshal [%+v] ,failed %s", *data, marshalErr.Error())
		return marshalErr
	}
	data.MethodsInDB = string(methodsBs)
	data.Host = common.UniqueHost //机器唯一编号
	var dataInDb DeployInfoModel
	queryErr := db.GlobalDB.Model(&DeployInfoModel{}).Where("user_id = ?", data.UserId).Where("contract = ?", data.ContractName).First(&dataInDb).Error
	if queryErr != nil {
		if gorm.IsRecordNotFoundError(queryErr) {
			return db.GlobalDB.Model(&DeployInfoModel{}).Create(data).Error
		}
		log.Errorf("SaveDeployInfo data [%+v],failed %s",
			*data, queryErr.Error())
		return queryErr
	}
	return db.GlobalDB.Model(&DeployInfoModel{}).Where("user_id = ?", data.UserId).Where("contract = ?", data.ContractName).
		Update("src_md5 = ?", data.SrcMd5).Update("bin_md5 = ?", data.BinMd5).
		Update("build_time = ?", data.BuildTime).Update("host = ?", data.Host).
		Update("deploy_time = ?", data.DeployTime).Update("methods = ?", data.MethodsInDB).Error
}

func ConstructDeployInfoByCompileInfo(compile *CompileInfoModel) *DeployInfoModel {
	return &DeployInfoModel{
		UserId:       compile.UserId,
		ContractName: compile.ContractName,
		SrcMd5:       compile.SrcMd5,
		BinMd5:       compile.BinMd5,
		BuildTime:    compile.BuildTime,
		Methods:      compile.Methods,
		DeployTime:   time.Now().Unix(),
	}
}

func GetDeployInfo(userId string, contractName string) (*DeployInfoModel, error) {
	var dataInDb DeployInfoModel
	queryErr := db.GlobalDB.Model(&DeployInfoModel{}).Where("user_id = ?", userId).Where("contract = ?", contractName).First(&dataInDb).Error
	if queryErr != nil {
		return &dataInDb, queryErr
	}
	unmarshalErr := json.Unmarshal([]byte(dataInDb.MethodsInDB), &(dataInDb.Methods))
	return &dataInDb, unmarshalErr
}
